#ifndef _SKBOOKLIBRARY_HPP_
#define _SKBOOKLIBRARY_HPP_

#include <iostream>
#include "SKBookNode.hpp"
#include "SKBookList.hpp"
#include "SKBookStoreMap.hpp"
#include "SKThread.hpp"

using namespace std;

typedef void (*FPTR) (BookId bookId);

/**
 * @brief singleton class SKBookLibrary which holds all the library details.
 */
class SKBookLibrary
{
public:

    static SKBookLibrary& getInstance()
    {
	return skBookLibrary_;
    }

    bool initialize();
    bool AddBook(SKBookNode* book);
    bool removeBook(BookId bookId);
    bool isAvailableBookId(BookId bookId);
    void notifyOnAvailability(BookId bookId, FPTR notifyCallBack);
    SKBookNode* getBook(BookId bookId);
    void collectBook(BookId bookId);
    void displayBooksByAuthor(const std::string& authorName);
    void displayBooksByCategory(const std::string& category);
    void showAllBooks();

private:
    SKBookLibrary() {}
    SKBookLibrary(const SKBookLibrary&) {}
    SKBookLibrary& operator=(const SKBookLibrary&) {}
    static SKBookLibrary skBookLibrary_;

    // have all the maps here
    SKBookStoreMap<BookId, SKBookNode> bookStoreMap_;
    SKBookStoreMap<std::string, SKBookList> authorMap_;
    SKBookStoreMap<std::string, SKBookList> categoryMap_;
    SKBookStoreMap<BookId, FPTR> notificationMap_;

    // mutexes and conditional variables
    // any manipulation (addition and deletion) of the nodes will be protected
    // with mutexes and conditional variables.
    // Either of the operation will only be performed in order to not invalidate
    // memory

    // could better use atomic operations but not available on host.
    SKThread skThread_;
};

SKBookLibrary SKBookLibrary::skBookLibrary_;

#endif //_SKBOOKLIBRARY_HPP_
